/*
 * Copyright © 2019-2020  Whale Cloud, Inc. All Rights Reserved.
 *
 * Notice: Whale Cloud Inc copyrights this specification.
 * No part of this specification may be reproduced in any form or means,
 * without the prior written consent of Whale Cloud Inc.
 *
 */
package com.wteam.modules.system.service.impl;

import com.wteam.modules.system.domain.Course;
import com.wteam.modules.system.domain.CreditType;
import com.wteam.modules.system.domain.dto.CreditTypeDTO;
import com.wteam.modules.system.domain.dto.CusPage;
import com.wteam.modules.system.domain.mapper.CourseMapper;
import com.wteam.modules.system.domain.mapper.CreditTypeMapper;
import com.wteam.modules.system.domain.mapper.StudentMapper;
import com.wteam.modules.system.repository.CourseRepository;
import com.wteam.modules.system.repository.CreditTypeRepository;
import com.wteam.modules.system.repository.StudentRepository;
import com.wteam.modules.system.service.CreditRecordService;
import com.wteam.modules.system.domain.CreditRecord;
import com.wteam.modules.system.domain.dto.CreditRecordDTO;
import com.wteam.modules.system.domain.criteria.CreditRecordQueryCriteria;
import com.wteam.modules.system.domain.mapper.CreditRecordMapper;
import com.wteam.modules.system.repository.CreditRecordRepository;
import com.wteam.exception.BadRequestException;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import com.wteam.utils.*;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.cache.annotation.*;
import lombok.RequiredArgsConstructor;
import java.io.IOException;
import javax.servlet.http.HttpServletResponse;
import java.sql.Timestamp;
import java.util.*;

/**
 * 学分记录 业务实现层.
 *
 * @author herry_wong
 * @since 2020-12-29
 */
@Service
@RequiredArgsConstructor
@CacheConfig(cacheNames = "creditRecord")
@Transactional(readOnly = true, rollbackFor = Exception.class)
public class CreditRecordServiceImpl implements CreditRecordService {

    private final CreditRecordRepository creditRecordRepository;

    private final CreditRecordMapper creditRecordMapper;

    private final RedisUtils redisUtils;

    private final CourseRepository courseRepository;
    private final CourseMapper courseMapper;

    private StudentRepository studentRepository;
    private StudentMapper studentMapper;

    private CreditTypeRepository creditTypeRepository;
    private CreditTypeMapper creditTypeMapper;

    @Override
    public Map<String,Object> queryAll(CreditRecordQueryCriteria criteria, Pageable pageable){
        Page<CreditRecord> page = creditRecordRepository.findAll((root, criteriaQuery, criteriaBuilder) ->  QueryHelper.andPredicate(root, criteria, criteriaBuilder), pageable);
        Page<CreditRecordDTO> creditRecordDTOPage = page.map(creditRecordMapper::toDto);
        Page<CreditRecordDTO> cusPage = new CusPage<>(creditRecordDTOPage);
        for (CreditRecordDTO creditRecordDTO: cusPage){
            Collections.replaceAll(cusPage.getContent(),
                    creditRecordDTO,
                    findDTOById(creditRecordDTO.getId()));
        }
        return PageUtil.toPage(cusPage);
    }

    @Override
    public List<CreditRecordDTO> queryAll(CreditRecordQueryCriteria criteria){
        return creditRecordMapper.toDto(creditRecordRepository.findAll((root, criteriaQuery, criteriaBuilder) ->  QueryHelper.andPredicate(root,criteria,criteriaBuilder)));
    }

    @Override
//    @Cacheable(key = "'id:' + #p0")
    public CreditRecordDTO findDTOById(Long id) {
        CreditRecord creditRecord = creditRecordRepository.findById(id).orElse(null);
        ValidUtil.notNull(creditRecord, CreditRecord.ENTITY_NAME, "id", id);
        CreditRecordDTO creditRecordDTO = creditRecordMapper.toDto(creditRecord);
        creditRecordDTO.setCourseDTO(courseMapper.toDto(courseRepository.findByIdNoLogic(creditRecordDTO.getCourseId())));
        creditRecordDTO.setDailyScore(creditRecordDTO.getScore()*creditRecordDTO.getCourseDTO().getRadio());
        creditRecordDTO.setExamScore(creditRecordDTO.getScore()-creditRecordDTO.getDailyScore());
        creditRecordDTO.setStudentDTO(studentMapper.toDto(studentRepository.findByIdNoLogic(creditRecordDTO.getStudentId())));
        creditRecordDTO.setCreditTypeDTO(creditTypeMapper.toDto(creditTypeRepository.findByIdNoLogic(creditRecordDTO.getTypeId())));
        return creditRecordDTO;

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public CreditRecordDTO create(CreditRecord resources) {
        Course course = courseRepository.findById(resources.getCourseId()).orElse(null);
        if (course == null){
            CreditRecordDTO creditRecordDTO = new CreditRecordDTO();
            creditRecordDTO.setMsg("课程不存在");
            return creditRecordDTO;
        }

        if (course.getEndTime().after(new Timestamp(System.currentTimeMillis()))){
            CreditRecordDTO creditRecordDTO = new CreditRecordDTO();
            creditRecordDTO.setMsg("课程未结束");
            return creditRecordDTO;
        }

        Double totalScore = resources.getDailyScore()*course.getRadio()+resources.getExamScore()*(1-course.getRadio());
        resources.setScore(totalScore);
        resources.setTypeId(course.getTypeId());
        if (totalScore < 60){
            resources.setCredit(resources.getCredit());
        }
        return creditRecordMapper.toDto(creditRecordRepository.save(resources));
    }

    @Override
//    @CacheEvict(key = "'id:' + #p0.id")
    @Transactional(rollbackFor = Exception.class)
    public void update(CreditRecord resources) {
        CreditRecord creditRecord = creditRecordRepository.findById(resources.getId()).orElse(null);
        ValidUtil.notNull(creditRecord, CreditRecord.ENTITY_NAME, "id",resources.getId());

        creditRecord.copy(resources);
        creditRecordRepository.save(creditRecord);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteAll(Set<Long> ids) {
        redisUtils.delByKeys("creditRecord::id:", ids);
        creditRecordRepository.logicDeleteInBatchById(ids);
    }

    @Override
    public void download(List<CreditRecordDTO> queryAll, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (CreditRecordDTO creditRecord : queryAll) {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("学生id", creditRecord.getStudentId());
            map.put("学分类型", creditRecord.getTypeId());
            map.put("学分", creditRecord.getCredit());
            map.put("课程id", creditRecord.getCourseId());
            map.put("学科成绩", creditRecord.getScore());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }
}